#include "BondUtility.h"

#include <bondlib/AdditionBondInfo.h>
#include <bondlib/BondCDCPriceInfo.h>
#include <bondlib/BondContainer.h>
#include <bondlib/BondOptionInfo.h>
#include <core/ImageMgr.h>
#include <core/StyleMgr.h>
#include <core/time/date.h>
#include <core/time/system_time.h>
#include <qbprotocol/include/rdProto.h>
#include <qbtools/tools.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>
#include <widgets/STabCtrl.h>
#include <widgets/table/STable.h>

#include <QColor>
#include <QPointer>
#include <QStandardItem>
#include <algorithm>

#include "BondDataCenter.h"
#include "GridImage.h"
#include "StringResource.h"

void BondUtility::calcOptDate(const CBondInfo& bi, time_t& tm1, time_t& tm2) {
  tm1 = tm2 = 0;

  int optionIndex = bi.GetOptionInfoIndex();
  if (optionIndex < 0) return;
  const CBondOptionInfo* pOpi =
      CBondContainer::instance().GetBondOptionInfo(optionIndex);
  if (pOpi == nullptr) return;

  const char* callstr = pOpi->GetCallStr();  // 赎回行行权日;
  if (callstr != nullptr) {
    // 行权日排序
    std::vector<int> results;
    extractOptDate(callstr, results);
    if (results.size() != 0) tm1 = qb::base::getTimeFromInt(results[0]);
  }

  const char* putstr = pOpi->GetPutStr();  // 回售权行权日 ;
  if (putstr != NULL) {
    // 行权日排序
    std::vector<int> results;
    extractOptDate(putstr, results);
    if (results.size() != 0) tm1 = qb::base::getTimeFromInt(results[0]);
  }
}

void BondUtility::extractOptDate(const char* dateStr, std::vector<int>& dates) {
  dates.clear();
  if (!dateStr) return;

  QString str = QString::fromLocal8Bit(dateStr);
  QStringList strs = str.split('|');
  for (int i = 0; i < strs.length(); i += 2)
    dates.push_back(strs.at(i).toInt());

  std::sort(dates.begin(), dates.end());
  dates.erase(std::unique(dates.begin(), dates.end()), dates.end());
}

QString BondUtility::FormatBidLimitTop(const QString& strBid) {
  QString strFormatBid = "";
  QStringList l_array = strBid.split('.');
  if (l_array.length() > 1) {
    // 2016/08/03,bushion.xin:超过两位的小数，末尾的0删除
    QString strLeft = l_array[0];
    QString strRight = l_array[1];
    if (strRight.length() < 2) {
      strFormatBid = strBid;
      strFormatBid.append("0");
      return strFormatBid;
    } else {
      int nLen = strRight.length();
      int nSearchCount = 0;
      while (nLen > 2) {
        bool bZero = false;
        if (strRight[nLen - 1] == '0') {
          bZero = true;
        }
        if (bZero) {
          strRight.remove(nLen - 1, 1);
          nLen = strRight.length();
        } else {
          break;
        }

        // 防止死循环,
        if (nSearchCount < 10)
          ++nSearchCount;
        else
          break;
      }
      strFormatBid = strLeft + "." + strRight;
      return strFormatBid;
    }
  } else {
    if (strBid == "--" || strBid.isEmpty()) {
      return strBid;
    } else {
      strFormatBid = strBid;
      strFormatBid.append(".00");
      return strFormatBid;
    }
  }

  return strFormatBid;
}

void BondUtility::FormatWholeMktDealPrice(QString& strPrice,
                                          const char* cParam) {
  strPrice = "--";
  if (strlen(cParam) > 0) {
    strPrice =
        QString::fromLocal8Bit(SSTools::PriceRemoveZero(cParam, 2).c_str());
    if (strPrice.isEmpty()) strPrice = "--";
  }
}

int BondUtility::getFirstIssueBondInfo(const char* cComBondKey) {
  int bondIndex = CBondContainer::instance().GetBondIndex(cComBondKey);
  if (!CBondContainer::instance().IsValidIndex(bondIndex)) return -1;

  const CBondInfo& bi = CBondContainer::instance().ElementAtR(bondIndex);
  if (!bi.IsAddIssueBond()) return bondIndex;

  const CAdditionBondInfo* addInfo = bi.GetAdditionInfo();
  if (!addInfo) return bondIndex;

  const char* firstKey = addInfo->GetFirstIssueKey();
  if (!firstKey) return bondIndex;

  int bondIndex2 = CBondContainer::instance().GetBondIndex(firstKey);
  if (!CBondContainer::instance().IsValidIndex(bondIndex2)) return bondIndex;

  return bondIndex2;
}

int BondUtility::getBondDetailKlineBeginTime() {
  time_t ctCurrent = ServerTimeMgr::instance().serverTime();
  int nDayTime = 24 * 60 * 60;
  int nBeginDate = qb::base::IntDate::timeToInt(ctCurrent + nDayTime);
  const CUserMemberInfo& userInfo =
      SSUserAccountManager::instance().GetUserMemberInfo();
  if (strcmp(userInfo.m_IsPaidCustom, "1") == 0) {
    nBeginDate = -1;
  } else {
    if (strcmp(userInfo.m_MemberLevel, "5") == 0 ||
        strcmp(userInfo.m_MemberLevel, "4") == 0) {
      nBeginDate = qb::base::IntDate::timeToInt(ctCurrent - 90 * nDayTime);
    } else if (strcmp(userInfo.m_MemberLevel, "3") == 0 ||
               strcmp(userInfo.m_MemberLevel, "2") == 0) {
      nBeginDate = qb::base::IntDate::timeToInt(ctCurrent - 30 * nDayTime);
    }
  }
  return nBeginDate;
}

int BondUtility::GetInterestBeginTime(CBondInfo& bondInfo, int nReq) {
  if (nReq == E_FID_QB_BOND_CREDIT_SPREAD_REQ &&
      !bondInfo.is_interest_bond()) {  // 个券信用利差需要剔除
    std::string stWarrant = bondInfo.GetWarrant();
    bool bCheckWarr = (strstr(bondInfo.GetWarrant(), "GUA") != nullptr) ||
                      (strstr(bondInfo.GetWarrant(), "SEC") != nullptr);
    bool bCheckNCD = bondInfo.IsBondNCD();
    bool bCheckPriva = bondInfo.IsBondPrivate();
    bool bCheckCoup = (strcmp("FRN", bondInfo.GetCouponType()) == 0 ||
                       strcmp("DSC", bondInfo.GetCouponType()) == 0);
    bool bCheckSubType = (strcmp("BGB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("SGB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("EGB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("SCB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("LLB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("TLB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("PBB", bondInfo.GetBondSubType()) == 0 ||
                          strcmp("PPN", bondInfo.GetBondSubType()) == 0);
    if (bCheckCoup || bCheckSubType || bCheckWarr || bCheckNCD || bCheckPriva) {
      return -2;
    }
  }

  bool bCurveThis = false, bCurveHis = false, bBondThis = false,
       bBondHis = false;
  auto& auth = SSUserAccountManager::instance().GetCDCAutority();
  if (auth.find(8) != auth.end()) bCurveThis = true;  // 收益率曲线 - 当年
  if (auth.find(9) != auth.end()) bCurveHis = true;  // 收益率曲线 - 历史
  if (auth.find(10) != auth.end()) bBondHis = true;  // 估值数据 - 历史
  if (bondInfo.IsValidBond() && bondInfo.IsCDCAuthValid()) bBondThis = true;
  if ((bBondThis && bCurveThis) || (bBondHis && bCurveHis)) {
    return -1;  // 约定恒值-1
  }

  return -2;
}

int BondUtility::makeTypeOperate(int type, int operate) {
  if (type == 1) return change;
  if (type == 2) {
    if (operate == 0)
      return token;
    else if (operate == 1)
      return given;
    else if (operate == 2)
      return trade;
  }
  return -1;
}

void BondUtility::translateDonePrice(const QString& ctPrice, QString& strTemp) {
  strTemp = "";
  if (ctPrice.isEmpty()) return;

  strTemp = SSTools::PriceRemoveZero(ctPrice, 2);
}

bool BondUtility::isTransBond(const CBondInfo& info) {
  if (strcmp(info.GetBondSubType(), "CVB") == 0 ||
      strcmp(info.GetBondSubType(), "SCV") == 0)
    return true;
  return false;
}

QString BondUtility::GetReqDataCombKey(const CBondInfo* pBondInfo) {
  QString strReqCombKey;
  if (pBondInfo) {
    if (pBondInfo->IsAddIssueBond()) {
      const CAdditionBondInfo* addInfo =
          (const_cast<CBondInfo*>(pBondInfo))->GetAdditionInfo();
      if (!addInfo) return "";
      QString strFirstKey = QString("%1").arg(addInfo->GetFirstIssueKey());
      if (!strFirstKey.isEmpty() && strcmp(strFirstKey.toStdString().c_str(),
                                           pBondInfo->GetCombBondKey()) != 0) {
        strReqCombKey = strFirstKey;
      } else {
        // 没有找到原券
      }
    } else {
      strReqCombKey = pBondInfo->GetCombBondKey();
    }
  }

  return strReqCombKey;
}

bool BondUtility::updateBestPriceVersionByID(CBondContainer& container,
                                             const char* pComId, int nMinver,
                                             int nMaxver, time_t nTime) {
  std::string strCompId = pComId;
  int nVer = container.GetVersionById(strCompId);
  if (nVer == -1 || nVer + 1 == nMinver) {
    container.UpdateVersionById(strCompId, nMaxver, nTime);
    return false;
  } else if (nVer + 1 < nMinver) {
    container.UpdateVersionById(strCompId, nMaxver, nTime);
  } else if (nVer >= nMaxver)
    return false;

  return true;
}

bool BondUtility::transfBestPriceToMarketStream(const xQBBestPriceUnit_c& best,
                                                xQBMarketStreamUnit_c& ms) {
  memset(&ms, 0, sizeof(xQBMarketStreamUnit_c));

  CBondContainer& bc = CBondContainer::instance();
  int nIndex = bc.GetBondIndex(best.m_bondkey, best.m_listedmarket);
  if (nIndex < 0 || nIndex >= bc.GetSize()) return false;

  REPORT rep;
  memset(&rep, 0, sizeof(REPORT));
  bc.GetCompanyRepById(nIndex, best.m_company_id, rep);

  FIELDCOPY(ms.m_company_id, best.m_company_id);
  // FIELDCOPY(ms.m_company_name,best.m_company_name);
  FIELDCOPY(ms.m_type, "1");
  ms.m_modify_time = rep.m_create_time;  // datetime,
  ms.m_create_time = rep.m_create_time;  // datetime,

  ms.m_body1.m_createTime = rep.m_create_time;
  // FIELDCOPY(ms.m_body1.m_bondCode,best.m_bond_code);
  FIELDCOPY(ms.m_body1.m_bondkey, best.m_bondkey);
  FIELDCOPY(ms.m_body1.m_listedmarket, best.m_listedmarket);
  // FIELDCOPY(ms.m_body1.m_bondShortName,best.m_bond_shorname);

  if (strcmp(rep.m_bidinfo.m_bp_status, "0") != 0) {
    memset(ms.m_body1.m_bidOfferId, 0, sizeof(ms.m_body1.m_bidOfferId));
    memset(ms.m_body1.m_bidprice, 0, sizeof(ms.m_body1.m_bidprice));
    memset(ms.m_body1.m_bid_cleanprice, 0, sizeof(ms.m_body1.m_bid_cleanprice));
    memset(ms.m_body1.m_bid_yield, 0, sizeof(ms.m_body1.m_bid_yield));
    memset(ms.m_body1.m_bidvolume, 0, sizeof(ms.m_body1.m_bidvolume));
    memset(ms.m_body1.m_bidRebate, 0, sizeof(ms.m_body1.m_bidRebate));
    memset(ms.m_body1.m_bidReturn_point, 0,
           sizeof(ms.m_body1.m_bidReturn_point));
    memset(ms.m_body1.m_bidflag_bargain, 0,
           sizeof(ms.m_body1.m_bidflag_bargain));
    memset(ms.m_body1.m_bidflag_relation, 0,
           sizeof(ms.m_body1.m_bidflag_relation));
    memset(ms.m_body1.m_bid_description, 0,
           sizeof(ms.m_body1.m_bid_description));
    memset(ms.m_body1.m_bid_interpret, 0, sizeof(ms.m_body1.m_bid_interpret));
    memset(ms.m_body1.m_bidQuotetype, 0, sizeof(ms.m_body1.m_bidQuotetype));
  } else {
    FMTBUF(ms.m_body1.m_bidOfferId, "%d", rep.m_dwVersion);
    if (strcmp(rep.m_bidinfo.m_sPrice, "Bid") != 0)
      FIELDCOPY(ms.m_body1.m_bidprice, rep.m_bidinfo.m_sPrice);
    FIELDCOPY(ms.m_body1.m_bid_cleanprice, rep.m_bidinfo.m_clean_price);
    FIELDCOPY(ms.m_body1.m_bid_yield, rep.m_bidinfo.m_yield_price);
    FIELDCOPY(ms.m_body1.m_bidvolume, rep.m_bidinfo.m_sVolume);
    FIELDCOPY(ms.m_body1.m_bidRebate, rep.m_bidinfo.m_rebate);
    FIELDCOPY(ms.m_body1.m_bidReturn_point, rep.m_bidinfo.m_return_point);
    FIELDCOPY(ms.m_body1.m_bidflag_bargain, rep.m_bidinfo.m_flag_bargain);
    FIELDCOPY(ms.m_body1.m_bidflag_relation, rep.m_bidinfo.m_flag_relation);
    // m_bidExercise[2];				//行权到期  (0-行权
    // 1-到期)
    FIELDCOPY(ms.m_body1.m_bid_description, rep.m_bidinfo.m_description);
    FIELDCOPY(ms.m_body1.m_bid_interpret, rep.m_bidinfo.m_interpret);
    FIELDCOPY(ms.m_body1.m_bidQuotetype, rep.m_bidinfo.m_quotetype);
  }

  if (strcmp(rep.m_askinfo.m_bp_status, "0") != 0) {
    memset(ms.m_body1.m_ofrOfferId, 0, sizeof(ms.m_body1.m_ofrOfferId));
    memset(ms.m_body1.m_ofrprice, 0, sizeof(ms.m_body1.m_ofrprice));
    memset(ms.m_body1.m_ofr_cleanprice, 0, sizeof(ms.m_body1.m_ofr_cleanprice));
    memset(ms.m_body1.m_ofr_yield, 0, sizeof(ms.m_body1.m_ofr_yield));
    memset(ms.m_body1.m_ofrvolume, 0, sizeof(ms.m_body1.m_ofrvolume));
    memset(ms.m_body1.m_ofrRebate, 0, sizeof(ms.m_body1.m_ofrRebate));
    memset(ms.m_body1.m_ofrReturn_point, 0,
           sizeof(ms.m_body1.m_ofrReturn_point));
    memset(ms.m_body1.m_ofrflag_bargain, 0,
           sizeof(ms.m_body1.m_ofrflag_bargain));
    memset(ms.m_body1.m_ofrflag_relation, 0,
           sizeof(ms.m_body1.m_ofrflag_relation));
    memset(ms.m_body1.m_ofr_description, 0,
           sizeof(ms.m_body1.m_ofr_description));
    memset(ms.m_body1.m_ofr_interpret, 0, sizeof(ms.m_body1.m_ofr_interpret));
    memset(ms.m_body1.m_ofrQuotetype, 0, sizeof(ms.m_body1.m_ofrQuotetype));
  } else {
    FMTBUF(ms.m_body1.m_ofrOfferId, "%d", rep.m_dwVersion);
    if (strcmp(rep.m_bidinfo.m_sPrice, "Ofr") != 0)
      FIELDCOPY(ms.m_body1.m_ofrprice, rep.m_askinfo.m_sPrice);
    FIELDCOPY(ms.m_body1.m_ofr_cleanprice, rep.m_askinfo.m_clean_price);
    FIELDCOPY(ms.m_body1.m_ofr_yield, rep.m_askinfo.m_yield_price);
    FIELDCOPY(ms.m_body1.m_ofrvolume, rep.m_askinfo.m_sVolume);
    FIELDCOPY(ms.m_body1.m_ofrRebate, rep.m_askinfo.m_rebate);
    FIELDCOPY(ms.m_body1.m_ofrReturn_point, rep.m_askinfo.m_return_point);
    FIELDCOPY(ms.m_body1.m_ofrflag_bargain, rep.m_askinfo.m_flag_bargain);
    FIELDCOPY(ms.m_body1.m_ofrflag_relation, rep.m_askinfo.m_flag_relation);
    // m_ofrExercise[2]
    FIELDCOPY(ms.m_body1.m_ofr_description, rep.m_askinfo.m_description);
    FIELDCOPY(ms.m_body1.m_ofr_interpret, rep.m_askinfo.m_interpret);
    FIELDCOPY(ms.m_body1.m_ofrQuotetype, rep.m_askinfo.m_quotetype);
  }

  return true;
}

static bool GetVolAndDesc(const char* interpret, BYTE btSett,
                          std::string& strVol, std::string& strDesc,
                          bool onlyCheck, bool bIsCfets) {
  if (bIsCfets) {
    switch (btSett) {
      case 0x1: {
        if (strDesc.find("T+0") != strDesc.npos) return true;
        break;
      }
      case 0x2: {
        if (strDesc.find("T+1") != strDesc.npos) return true;
        break;
      }
      default:
        break;
    }
    return false;
  }
  PRICE_SETTLEMENT_LIST pss;
  CBondContainer::DecodeSettlement(interpret, pss);
  bool found = false;
  for (auto& ps : pss) {
    if (0 == (ps.m_type & btSett)) continue;

    if (onlyCheck) return true;

    if (!strVol.empty()) strVol.append("+");

    if (!strDesc.empty()) strDesc.append("+");

    strVol.append(ps.m_vol);
    if (strlen(ps.m_desc) > 0)
      strDesc.append(ps.m_vol).append("(").append(ps.m_desc).append(")");
    else
      strDesc.append(ps.m_vol);
    found = true;
  }

  return found;
}

bool BondUtility::updateMarketStreamBySettlement(xQBMarketStreamUnit_c& ms,
                                                 BYTE btSett, bool onlyCheck,
                                                 bool bIsCfets) {
  if (strcmp(ms.m_type, "1") != 0) return false;

  std::string strVol;
  strVol.reserve(sizeof(ms.m_body1.m_bidvolume));

  std::string strDesc;
  strDesc.reserve(sizeof(ms.m_body1.m_bid_description));

  bool hasBidSettlementData = false;
  if (ms.m_body1.m_bidOfferId[0] != '\0') {
    if (bIsCfets) {
      strDesc = ms.m_body1.m_bid_description;
    }
    hasBidSettlementData = GetVolAndDesc(ms.m_body1.m_bid_interpret, btSett,
                                         strVol, strDesc, onlyCheck, bIsCfets);
    if (onlyCheck && hasBidSettlementData) return true;

    if (!onlyCheck) {
      if (hasBidSettlementData) {
        if (!bIsCfets) {
          FIELDCOPY(ms.m_body1.m_bidvolume, strVol.c_str());
          if (strDesc.find('(') != -1)
            FIELDCOPY(ms.m_body1.m_bid_description, strDesc.c_str());
          else
            memset(ms.m_body1.m_bid_description, 0,
                   sizeof(ms.m_body1.m_bid_description));
        }
      } else {
        memset(ms.m_body1.m_bidvolume, 0, sizeof(ms.m_body1.m_bidvolume));
        memset(ms.m_body1.m_bid_description, 0,
               sizeof(ms.m_body1.m_bid_description));
        memset(ms.m_body1.m_bidprice, 0, sizeof(ms.m_body1.m_bidprice));
        memset(ms.m_body1.m_bidOfferId, 0, sizeof(ms.m_body1.m_bidOfferId));
        memset(ms.m_body1.m_bid_yield, 0, sizeof(ms.m_body1.m_bid_yield));
        memset(ms.m_body1.m_bid_cleanprice, 0,
               sizeof(ms.m_body1.m_bid_cleanprice));
      }
    }
  }

  strVol.clear();
  strDesc.clear();
  bool hasOfrSettlementData = false;
  if (ms.m_body1.m_ofrOfferId[0] != '\0') {
    if (bIsCfets) {
      strDesc = ms.m_body1.m_ofr_description;
    }
    hasOfrSettlementData = GetVolAndDesc(ms.m_body1.m_ofr_interpret, btSett,
                                         strVol, strDesc, onlyCheck, bIsCfets);
    if (onlyCheck && hasOfrSettlementData) return true;

    if (!onlyCheck) {
      if (hasOfrSettlementData) {
        if (!bIsCfets) {
          FIELDCOPY(ms.m_body1.m_ofrvolume, strVol.c_str());
          if (strDesc.find('(') != -1)
            FIELDCOPY(ms.m_body1.m_ofr_description, strDesc.c_str());
          else
            memset(ms.m_body1.m_ofr_description, 0,
                   sizeof(ms.m_body1.m_ofr_description));
        }
      } else {
        memset(ms.m_body1.m_ofrvolume, 0, sizeof(ms.m_body1.m_ofrvolume));
        memset(ms.m_body1.m_ofr_description, 0,
               sizeof(ms.m_body1.m_ofr_description));
        memset(ms.m_body1.m_ofrprice, 0, sizeof(ms.m_body1.m_ofrprice));
        memset(ms.m_body1.m_ofrOfferId, 0, sizeof(ms.m_body1.m_ofrOfferId));
        memset(ms.m_body1.m_ofr_yield, 0, sizeof(ms.m_body1.m_ofr_yield));
        memset(ms.m_body1.m_ofr_cleanprice, 0,
               sizeof(ms.m_body1.m_ofr_cleanprice));
      }
    }
  }

  return hasBidSettlementData || hasOfrSettlementData;
}

void BondUtility::setCFETSCompany(int nType, const std::string& stName,
                                  QString& txt, QString& tip) {
  if (nType == em_cfets_xBond) {
    txt = QObject::tr("匿名");
    return;
  }
  QString nameStr = QString::fromLocal8Bit(stName.c_str());
  if (nameStr.isEmpty()) {
    txt = "--";
  } else {
    QStringList stArr = nameStr.split("|");
    if (stArr.length() == 1) {
      txt = nameStr;
    } else {
      // itm.nTextStyle = 88;  //TODO 干啥的？
      txt = QObject::tr("多家");
      nameStr = "";
      for (int nL = 0; nL < stArr.size(); nL++) {
        nameStr += stArr[nL];
        if (nL != stArr.size() - 1) nameStr += "\n";
      }
      tip = nameStr;
    }
  }
}

QColor BondUtility::brokerColor(int brokerid) {
  QColor clr = StyleMgr::instance().color("BasicBtn_Filter_Tittle");
  switch (brokerid) {
    case 1:
      clr = StyleMgr::instance().color("BrokerTP");
      break;
    case 2:
      clr = StyleMgr::instance().color("BrokerICAP");
      break;
    case 3:
      clr = StyleMgr::instance().color("BrokerBGC");
      break;
    case 4:
      clr = StyleMgr::instance().color("BrokerPA");
      break;
    case 5:
      clr = StyleMgr::instance().color("BrokerXT");
      break;
    case 6:
      clr = StyleMgr::instance().color("BrokerUEDA");
      break;
    case 50:
      clr = StyleMgr::instance().color("XBond");
      break;
    case 98:
      clr = StyleMgr::instance().color("BrokerSS");
      break;
    case 99:
      clr = StyleMgr::instance().color("BrokerBest");
      break;
    case 'e':
      clr = StyleMgr::instance().color("Shangjiaosuo_L2");
      break;
    default:
      break;
  }
  return clr;
}
STabCtrl* BondUtility::createBrokerTab(QWidget* parent, bool fixedSize,
                                       bool hasMixedBroker) {
  STabCtrl* tab = new STabCtrl(parent);
  const char* qbLicense =
      SSUserAccountManager::instance().GetPermission().GetValue(
          USER_PERMISSION_QB_PRO);
  const char* qbBroker =
      SSUserAccountManager::instance().GetPermission().GetValue(
          USER_PERMISSION_BROKER_BESTQUOTE);
  bool showAll = ((strcmp(qbLicense, "0") == 0 && strcmp(qbBroker, "1") == 0) ||
                  strcmp(qbLicense, "1") == 0 || strcmp(qbLicense, "2") == 0);

  if (showAll) {
    tab->addTab(QObject::tr("全部"));
    tab->showSelBorder(0, true, "TabSelBorder");
  }

  // 最优报价
  if (hasMixedBroker &&
      atoi(SSUserAccountManager::instance().GetPermission().GetValue(
          USER_PERMISSION_BOND_BESTQUOTE)) == 1) {
    tab->addTab(NewStringTable::strDlgQuote(64));
    int index = tab->getTabCount() - 1;
    tab->setTabData(index, QB_BROKER_BESTQUOTE);
    tab->setTabBkColor(index, brokerColor(QB_BROKER_BESTQUOTE));
    tab->setTabDragable(index, true);
    tab->showSelBorder(index, true, "TabSelBorder");
  }

  const CBrokerList& brokerList =
      SSUserAccountManager::instance().GetReadonlyBroker();
  std::vector<int> sortID = brokerList.GetSortKey();

  int nSortid = 0;
  CBrokerUnit stUnit;
  for (int i = 0; i < (int)sortID.size(); i++) {
    nSortid = sortID[i];
    for (CBrokerList::BrokerMap::const_iterator itor =
             brokerList.GetBrokerMap().begin();
         itor != brokerList.GetBrokerMap().end(); ++itor) {
      stUnit = itor->second;
      if (!CBrokerList::IsValidBroker(stUnit.m_brokerID)) continue;
      if (stUnit.m_brokerID != nSortid ||
          (!stUnit.m_enableFlag_BOND && !stUnit.m_enableFlag_NCD))
        continue;

      tab->addTab(QString::fromLocal8Bit(itor->second.m_brokerName.c_str()));
      int index = tab->getTabCount() - 1;
      tab->setTabData(index, stUnit.m_brokerID);
      tab->setTabBkColor(index, brokerColor(stUnit.m_brokerID));
      tab->setTabDragable(index, true);

      if (6 == stUnit.m_brokerID) {
        tab->showSelBorder(index, false, "ContactBlack");
      }

      break;
    }
  }

  if (tab->getTabCount() == 0) {
    tab->setParent(nullptr);
    delete tab;
    tab = nullptr;
  } else if (fixedSize)
    tab->setFixedSize(80 * tab->getTabCount(), 24);

  QObject::connect(tab, &STabCtrl::tabSeqChanged, [tab]() {
    std::vector<int> sortIds;
    int count = tab->getTabCount();
    for (int i = 0; i < count; ++i) {
      QVariant data = tab->tabData(i);
      if (!data.isValid()) continue;
      sortIds.push_back(data.toInt());
    }

    BondDataCenter::instance().requestQBCompanySort(sortIds.size(), sortIds);
  });

  QPointer<STabCtrl> guardTab(tab);
  QObject::connect(
      &BondDataCenter::instance(), &BondDataCenter::companySorted,
      [guardTab]() {
        if (guardTab.isNull()) return;

        const CBrokerList& brokerList =
            SSUserAccountManager::instance().GetReadonlyBroker();
        std::vector<int> sortID = brokerList.GetSortKey();
        int count = guardTab->getTabCount();

        int index = 0;
        for (int i = 0; i < count; ++i) {
          QVariant data = guardTab->tabData(i);
          if (!data.isValid()) continue;
          CBrokerUnit stUnit;
          int nSortid = sortID[index];
          for (CBrokerList::BrokerMap::const_iterator itor =
                   brokerList.GetBrokerMap().begin();
               itor != brokerList.GetBrokerMap().end(); ++itor) {
            stUnit = itor->second;
            if (!CBrokerList::IsValidBroker(stUnit.m_brokerID)) continue;
            if (stUnit.m_brokerID != nSortid ||
                (!stUnit.m_enableFlag_BOND && !stUnit.m_enableFlag_NCD))
              continue;

            guardTab->setTabText(
                i, QString::fromLocal8Bit(itor->second.m_brokerName.c_str()));
            guardTab->setTabData(i, stUnit.m_brokerID);
            guardTab->setTabBkColor(i, brokerColor(stUnit.m_brokerID));
            break;
          }

          ++index;
        }
      });
  return tab;
}

void BondUtility::DisplayVolumn(const PRICE& varPrice, bool bValid,
                                bool bExchange, QStandardItem* item) {
  item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                Qt::TextAlignmentRole);

  if (!bValid) {
    item->setData("--", Qt::DisplayRole);
    return;
  }

  if (strcmp(varPrice.m_description, "") != 0) {
    PRICE_SETTLEMENT_LIST lstPrc;
    CBondContainer::DecodeSettlement(varPrice.m_interpret, lstPrc);
    bool hasDesc = false, hasPStar = false, hasStar = false;
    std::string description;
    if (!lstPrc.empty()) {
      bool first = true;
      std::string vol;
      std::string desc;
      for (auto it : lstPrc) {
        vol = it.m_vol;
        desc = it.m_desc;
        if (!first) {
          vol = " + " + vol;
        }
        if (!desc.empty()) {
          vol += "(" + desc + ")";
          hasDesc = true;
        }
        if (it.m_pstar == '1') hasPStar = true;
        if (it.m_bargin > '0') hasStar = true;
        description.append(vol.c_str());
        first = false;
      }
    }

    if (hasPStar) {
      description += QString("\r\n报量后的*：表示可部分执行报价，即P*")
                         .toLocal8Bit()
                         .data();
    }
    if (hasStar) {
      description +=
          QString("\r\n备注中的*：表示意向性报价").toLocal8Bit().data();
    }

    item->setData(QString::fromLocal8Bit(description.c_str()), Qt::ToolTipRole);

    item->setData(BondUtility::gridImage(grid_flag_triangle),
                  Qt::DecorationRole);
  }

  QString txt = SSTools::StringRemoveZero(varPrice.m_sVolume);
  if (bExchange && (txt.length() <= 0 || txt.toFloat() < 0.00001f)) txt = "--";
  item->setData(txt, Qt::DisplayRole);
}

void BondUtility::DisplayCFETSVolumn(const CFETSQUOTE& varPrice, bool bBid,
                                     QStandardItem* item) {
  QString txt;
  if (bBid) {
    txt = SSTools::StringRemoveZero(varPrice.m_BidVol, true);
    if (strcmp(varPrice.m_bidVolDescription, "") != 0) {
      item->setData(QString::fromLocal8Bit(varPrice.m_bidVolDescription),
                    Qt::ToolTipRole);
    }
  } else {
    txt = SSTools::StringRemoveZero(varPrice.m_OfrVol, true);
    if (strcmp(varPrice.m_ofrVolDescription, "") != 0) {
      item->setData(QString::fromLocal8Bit(varPrice.m_ofrVolDescription),
                    Qt::ToolTipRole);
    }
  }

  if (txt.isEmpty()) txt = "--";
  item->setData(txt, Qt::DisplayRole);
}

void BondUtility::DisplayCFETSCompany(
    const CCFETSQuote::CFETSQUOTETYPE& cfets_quote_type,
    const std::string& stName, QStandardItem* item) {
  if (cfets_quote_type == CCFETSQuote::XBOND) {
    item->setData(QString("匿名"), Qt::DisplayRole);
    return;
  }
  QString strName = QString::fromLocal8Bit(stName.c_str());
  if (strName.isEmpty()) {
    item->setData(QString("--"), Qt::DisplayRole);
  } else {
    QStringList sArr = strName.split("|");
    const int nSz = sArr.size();
    if (nSz == 1) {
      item->setData(strName, Qt::DisplayRole);
    } else {
      item->setData(QString("多家"), Qt::DisplayRole);
      strName.clear();
      for (int nL = 0; nL < nSz; nL++) {
        strName += sArr[nL];
        if (nL != nSz - 1) strName += "\n";
      }
      item->setData(strName, Qt::ToolTipRole);
    }
  }
}

QString BondUtility::CheckStarBySettlement(const PRICE& varPrice,
                                           int& nStarFlag) {
  int nFlag = -1;
  PRICE_SETTLEMENT_LIST pdList;
  CBondContainer::DecodeSettlement(varPrice.m_interpret, pdList);
  for (auto& it : pdList) {
    if (it.m_bargin == '0' || it.m_bargin == '\0') {
      nFlag = 0;
      break;  // 显示优先级 无 > * > **
    } else if (it.m_bargin == '1') {
      nFlag = 1;
    } else if (it.m_bargin == '2' && nFlag < 0) {
      nFlag = 2;
    }
  }

  if (nFlag == 2)
    nStarFlag = 3;
  else if (nFlag == 1)
    nStarFlag = 1;
  else
    nStarFlag = -1;

  return NewStringTable::strQuoteFlag(nStarFlag);
}

QString BondUtility::CheckStar(const PRICE& varPrice, int& nStarFlag) {
  if (strcmp(varPrice.m_flag_bargain, "2") == 0) {
    nStarFlag = 3;
  } else if (strcmp(varPrice.m_flag_bargain, "1") == 0 ||
             strcmp(varPrice.m_flag_bargain, "true") == 0) {
    nStarFlag = 1;
  } else {
    nStarFlag = -1;
  }
  return NewStringTable::strQuoteFlag(nStarFlag);
}

void BondUtility::DisplayPriceNew(const PRICE& varPrice, bool bValid,
                                  QColor clrHLight, bool bExchange,
                                  bool isTransBond, bool bFixedPrefix,
                                  bool bTiny, bool checkSettlement,
                                  QStandardItem* item) {
  item->setData(clrHLight, Qt::ForegroundRole);
  item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                Qt::TextAlignmentRole);
  if (!bValid) {
    item->setData("--", Qt::DisplayRole);
    return;
  }

  int nStarFlag = -1;
  QString strDesc = checkSettlement ? CheckStarBySettlement(varPrice, nStarFlag)
                                    : CheckStar(varPrice, nStarFlag);
  if (nStarFlag != -1) {
    item->setData(
        BondUtility::gridImage((EnumImgFlag)(grid_flag_oco + nStarFlag)),
        PostfixImgRole);
    item->setData(strDesc, PostfixTipRole);
  }

  QString strTemp = "";
  if (bExchange) {
    if (isTransBond)
      strTemp = SSTools::FormatePrice(varPrice.m_clean_price);
    else
      strTemp = SSTools::FormatePrice(varPrice.m_sPrice);

    if (strTemp.toFloat() < 0.00001f) strTemp = "--";
  } else {
    strTemp = SSTools::FormatePrice(varPrice.m_sPrice);
    if (strTemp.isEmpty()) strTemp = "--";

    if (strTemp != "--") {
      int qt = atoi(varPrice.m_quotetype);
      if (qt == 1)  // 净价
      {
        item->setData(BondUtility::gridImage(bTiny ? tiny_tag_net_price
                                                   : grid_tag_netprice),
                      PrefixImgRole);
        item->setData(NewStringTable::strClean(), PrefixTipRole);
      } else if (qt == 2)  // 全价
      {
        item->setData(BondUtility::gridImage(bTiny ? tiny_tag_full_price
                                                   : grid_tag_fullprice),
                      PrefixImgRole);
        item->setData(NewStringTable::strFull(), PrefixTipRole);
      } else {
        // TODO
      }
    } else {
      // TODO
    }
  }
  item->setData(strTemp, Qt::DisplayRole);
}

void BondUtility::SetUpdateTimeCol(QStandardItem* item, time_t tTime) {
  const time_t& t_Current = tTime;
  QString txt;
  if (t_Current > 0) {
    qb::base::CTime stTime(tTime);
    qb::base::CTime stTimeTemp(stTime.GetYear(), stTime.GetMonth(),
                               stTime.GetDay(), 23, 59, 59);
    if (ServerTimeMgr::instance().serverTime() >
        stTimeTemp.GetTime()) {  // 过去的数据
      txt = NewStringTable::strYearMonthDay(stTime);
    } else {
      txt = QString("%1:%2:%3")
                .arg(stTime.GetHour(), 2, 10, QChar('0'))
                .arg(stTime.GetMinute(), 2, 10, QChar('0'))
                .arg(stTime.GetSecond(), 2, 10, QChar('0'));
    }
  }
  item->setData(txt, Qt::DisplayRole);
  item->setData(StyleMgr::instance().color("TextNormal"), Qt::ForegroundRole);
  item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                Qt::TextAlignmentRole);
}

QString BondUtility::getTakenCdcStr(
    const char* takenstr, const int nBondIndex,
    bool bIsCDCAuthValid) {  // 成交-中债,此处值作为显示
  if (takenstr == NULL || *takenstr == '\0') return "--";
  if (strcmp(takenstr, "--") == 0) return "--";
  double taken = CBondCDCPriceInfo::instance().GetYesterdayCDCPriceGap(
      bIsCDCAuthValid, nBondIndex, CBondCDCPriceInfo::price_type_yield, true,
      takenstr, INVALID_CDC_VALUE, false);
  if (taken <= INVALID_CDC_VALUE) return "--";
  return QString::number(taken, 'f', 2);
}
